package com.zebra.register;

import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.StrUtil;
import com.zebra.common.OnlineType;
import com.zebra.common.ZebraException;
import com.zebra.remoting.NotifyProxy;
import com.zebra.remoting.config.*;
import com.zebra.remoting.connection.Connection;
import com.zebra.remoting.protocol.CommandProfile;
import com.zebra.remoting.protocol.ZebraCommand;
import com.zebra.remoting.tms.TmsToRegisterMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@Slf4j
public class RegisterServerService {

    @Autowired
    private ServerRedisService serverRedisService;

    /**
     * 1，注册 TMS 同时写入 Redis
     * 2，如果有在线的GW列表；注册中心则需要向GW 发送 TMS 上线通知信息；
     * @param message
     * @return
     */
    public TmsServerInfo registerTmsAndRedis(TmsToRegisterMessage message)throws  Exception{
        if (null == message){
            throw new ZebraException("Register failure: info is null");
        }
        registerTms(message, true);
        printRegisterLog();
        return message.getServerInfo();
    }

    /**
     * 注册 GW 同时写入 Redis
     * @param serverInfo
     * @return
     */
    public GwRegisterResponse registerGwAndRedis(GatewayServerInfo serverInfo)throws Exception{
        if (null == serverInfo){
            throw new ZebraException("Register gateway failure: info is null");
        }
        registerGateway(serverInfo, true);
        //build gateway response
        GwRegisterResponse gwRegisterResponse = new GwRegisterResponse();
        gwRegisterResponse.setGwInfo(serverInfo);
        gwRegisterResponse.setTmsList(serverRedisService.findTmsMessage());
        gwRegisterResponse.setCmdSet(serverRedisService.findCMDList());
        printRegisterLog();
        return gwRegisterResponse;
    }

    /**
     * 注册 TMS 仅仅创建链接
     * @param message
     */
    public void connectTms(TmsToRegisterMessage message)throws Exception{
        if (null == message){
            throw new ZebraException("Register failure: info is null");
        }
        registerTms(message, false);
        printRegisterLog();
    }

    /**
     * 注册 Gateway 仅仅创建链接
     * @param serverInfo
     */
    public void connectGw(GatewayServerInfo serverInfo)throws  Exception{
        if (null == serverInfo){
            throw new ZebraException("Register failure: info is null");
        }
        registerGateway(serverInfo, false);
        printRegisterLog();
    }


    /**
     * 注册 TMS
     * @param tmsTrMsg
     */
    public void registerTms(TmsToRegisterMessage tmsTrMsg, boolean isRedis)throws Exception {
        if (null == tmsTrMsg || null == tmsTrMsg.getServerInfo() || ( isRedis == true && (null == tmsTrMsg.getCmds() || tmsTrMsg.getCmds().isEmpty()))){
            throw new ZebraException("Register failure: info is null");
        }
        RegisterServerInfo registerServerInfo = RegisterConfigInfoManager.getInstance().getRegisterServerInfo();
        if (null == registerServerInfo){
            throw new ZebraException("Register failure: RegisterServerInfo is null");
        }

        TmsServerInfo serverInfo = tmsTrMsg.getServerInfo();
        String inIP = serverInfo.getInIP().equals(NetUtil.getLocalhost().getHostAddress()) ? "127.0.0.1" : serverInfo.getInIP();

        Connection connection = RegisterClient.getInstance().connection(inIP, serverInfo.getPort(), serverInfo.getServerId(), ServerType.Tms);
        if (null == connection){
            throw new  Exception(StrUtil.format("Register TMS failure: Connection is null ip {} port {} ", inIP, serverInfo.getPort()));
        }

        if (isRedis){
            // add TMS to redis
            serverInfo.setOnline(OnlineType.Online.value());
            serverInfo.setOnlineNumber(0);
            serverRedisService.addTmsServer(serverInfo);
            connection.setServerId(serverInfo.getServerId());
            // add cmds
            serverRedisService.addCMDS(tmsTrMsg.getCmds());
        }

        ZebraCommand tmsRegister = ZebraCommand.builder().cmd(BasisCommandCode.REGISTER.cmd())
                .response(new RegisterConnectMessage(registerServerInfo.getServerId(), ServerType.Register.value()))
                .build();
        ZebraCommand registerCommand = (ZebraCommand) NotifyProxy.notifyProxy.syncMsg(connection.getChannel(), tmsRegister);
        if (null == registerCommand || StateCode.Success.code() != registerCommand.getState()){
            log.error("Register send RegisterConnectMessage to TMS failure  tmsInfo {}", serverInfo.toString());
            if (isRedis){
                serverRedisService.removeTms(serverInfo.getServerId());
            }
            throw new Exception("Register send RegisterConnectMessage to TMS failure");
        }

        //-----write--local--cache--
        RegisterConfigInfoManager.getInstance().registerTms(connection);

        //update register info
        if (registerServerInfo.addRsInfo(ServerType.Tms, serverInfo.getServerId())){
            serverRedisService.updateRegisterServer(registerServerInfo);
        }

        if (isRedis){
            notifyGW(serverInfo, tmsTrMsg.getCmds());
        }
    }

    // 【如果，Gateway已经有了则需要通知GW链接】
    private void notifyGW(TmsServerInfo serverInfo, List<CommandProfile> cmds){
        List<GatewayServerInfo> gwList = serverRedisService.findGwAll();
        if (null == gwList || gwList.isEmpty()){
            return;
        }

        GwRegisterMessage message = new GwRegisterMessage();
        message.setTms(serverInfo.toServerInfoMessage());
        message.setCmdList(cmds);
        ZebraCommand context = new ZebraCommand();
        context.setCmd(BasisCommandCode.RATOTMS.cmd());
        context.setResponse(message);

        for (GatewayServerInfo gwInfo : gwList){
            Connection connection = RegisterConfigInfoManager.getInstance().getGwConnection(gwInfo.getServerId());
            if (null == connection){
                try {
                    registerGateway(gwInfo, false);
                    connection = RegisterConfigInfoManager.getInstance().getGwConnection(gwInfo.getServerId());
                } catch (Exception e) {
                    log.error("Register Notfiy GW connnection TMS failure tms {}, gw {}", serverInfo.toString(), gwInfo.toString());
                }
            }
            if (null != connection && connection.isFine()){
                log.info("Register Notfiy GW connnection TMS  Ra_conn {} tms {} gw {} ", connection.toString(), serverInfo.toString(), gwInfo.toString());
                NotifyProxy.notifyProxy.pushMessage(connection.getChannel(), context);
            }
        }

    }

    public void registerGateway(GatewayServerInfo serverInfo, boolean isRedis)throws  Exception {
        RegisterServerInfo registerServerInfo = RegisterConfigInfoManager.getInstance().getRegisterServerInfo();
        if (null == registerServerInfo){
            throw new  Exception("Register failure: RegisterServerInfo is null");
        }

        String ip = 1 == serverInfo.getInner() ? serverInfo.getInIP() : serverInfo.getOutIP();
        Connection connection = RegisterClient.getInstance().connection(ip, serverInfo.getPort(), serverInfo.getServerId(), ServerType.Gateway);
        if (null == connection){
            throw new  Exception(StrUtil.format("Register Gateway failure: Connection is null ip {} port {} ", ip, serverInfo.getPort()));
        }

        if (isRedis){
            serverInfo.setOnline(OnlineType.Online.value());
            serverInfo.setOnlineNumber(0);
            serverRedisService.addGateway(serverInfo);  // add GW to redis
            connection.setServerId(serverInfo.getServerId());
        }

        ZebraCommand tmsRegister = ZebraCommand.builder().cmd(BasisCommandCode.REGISTER.cmd())
                .response(new RegisterConnectMessage(registerServerInfo.getServerId(), ServerType.Register.value()))
                .build();
        ZebraCommand registerCommand = (ZebraCommand) NotifyProxy.notifyProxy.syncMsg(connection.getChannel(), tmsRegister);
        if (null == registerCommand || StateCode.Success.code() != registerCommand.getState()){
            log.error("Register send RegisterConnectMessage to GW failure!  gwInfo {}", serverInfo.toString());
            if (isRedis){
                serverRedisService.removeGw(serverInfo.getServerId());
            }
            throw new Exception("Register send RegisterConnectMessage to GW failure");
        }

        //-----write--local--cache--
        RegisterConfigInfoManager.getInstance().registerGateways(connection);
        //update register info
        if (registerServerInfo.addRsInfo(ServerType.Gateway, serverInfo.getServerId())){
            serverRedisService.updateRegisterServer(registerServerInfo);
        }
    }


    //----update-Link-Tms-info------
    public void updateLinks(LINKSTORAmessage links){
        if (links.getServerType() == ServerType.Gateway.value()){
            GatewayServerInfo gatewayServerInfo = serverRedisService.getGwById(links.getServerId());
            if (null == gatewayServerInfo || links.getLinks().equals(gatewayServerInfo.getLinkTms())){
                return;
            }
            gatewayServerInfo.setLinkTms(links.getLinks());
            serverRedisService.updateGateway(gatewayServerInfo);
        }else if (links.getServerType() == ServerType.Tms.value()){
            TmsServerInfo tmsServerInfo = serverRedisService.getTmsById(links.getServerId());
            if (null == tmsServerInfo || links.getLinks().equals(tmsServerInfo.getLinkTms())){
                return;
            }
            tmsServerInfo.setLinkTms(links.getLinks());
            serverRedisService.updateTms(tmsServerInfo);
        }

    }
    //----update-OnlineNumber-Tms-info------
    public void updateOnlineNumber(ONNUMTORAmessage onlineMsg){
        if (onlineMsg.getServerType() == ServerType.Gateway.value()){
            GatewayServerInfo gatewayServerInfo = serverRedisService.getGwById(onlineMsg.getServerId());
            if (null == gatewayServerInfo || onlineMsg.getOnlineNumber() == gatewayServerInfo.getOnlineNumber()){
                return;
            }
            gatewayServerInfo.setOnlineNumber(onlineMsg.getOnlineNumber());
            serverRedisService.updateGateway(gatewayServerInfo);
        }else if (onlineMsg.getServerType() == ServerType.Tms.value()){
            TmsServerInfo tmsServerInfo = serverRedisService.getTmsById(onlineMsg.getServerId());
            if (null == tmsServerInfo || onlineMsg.getOnlineNumber() == tmsServerInfo.getOnlineNumber()){
                return;
            }
            tmsServerInfo.setOnlineNumber(onlineMsg.getOnlineNumber());
            serverRedisService.updateTms(tmsServerInfo);
        }

    }


    public void printRegisterLog(){
        log.info("---RA {}", RegisterConfigInfoManager.getInstance().getRegisterServerInfo().toString());
        log.info("---TMS {}", StrUtil.join(", ", RegisterConfigInfoManager.getInstance().getTmsServers()));
        log.info("---GW {}", StrUtil.join(", ", RegisterConfigInfoManager.getInstance().getGateways()));
    }



}
